package simon.tuke

import android.app.Application
import android.util.LruCache
import java.io.*
import java.util.*

/**
 * @author Simon
 */
object Tuke {

    @JvmStatic
    @Synchronized
    fun <T : Serializable?> write(key: String, value: T, isCache: Boolean) {
        try {
            val fileName = toFileName(key)
            val file = File((if (isCache) mCacheFilePath else mNoBackupFilePath) + fileName)
            if (!Objects.requireNonNull(file.parentFile).exists()) {
                file.parentFile?.mkdirs()
            }
            val stream = ObjectOutputStream(FileOutputStream(file))
            stream.writeObject(value)
            stream.close()
            //确认保存完成才添加到缓存
            if (value != null)
                mLcrCache.put(key, value)
        } catch (e: Exception) {
            throw e
        }
    }

    @JvmStatic
    @Synchronized
    operator fun <T : Serializable?> get(key: String, def: T): T {
        return get(key, def)
    }

    @JvmStatic
    @Synchronized
    operator fun <T : Serializable?> get(key: String, isCache: Boolean): T? {
        return get(key, isCache)
    }

    @JvmStatic
    @Synchronized
    operator fun <T : Serializable?> get(
        key: String,
        def: T,
        isCache: Boolean
    ): T {
        val fileName = toFileName(key)
        var value = mLcrCache[fileName] as T?
        return value ?: run {
            try {
                val file = File((if (isCache) mCacheFilePath else mNoBackupFilePath) + fileName)
                if (!Objects.requireNonNull(file.parentFile).exists()) {
                    file.parentFile?.mkdirs()
                }
                val stream = ObjectInputStream(FileInputStream(file))
                value = stream.readObject() as T?
                stream.close()
            } catch (e: Exception) {
                throw e
            }
            value ?: def
        }
    }

    private lateinit var mApplication: Application

    private val mMaxMemory = (Runtime.getRuntime().totalMemory() / 1024).toInt()
    private val mCacheSize = mMaxMemory / 100

    private val mLcrCache = LruCache<String, Serializable?>(mCacheSize)

    //非缓存目录路径
    private val mNoBackupFilePath: String
        get() = "${mApplication.noBackupFilesDir}/data/"

    //缓存目录路径
    private val mCacheFilePath: String
        get() = "${mApplication.cacheDir}/data/"

    private fun toFileName(key: String): String {
        return key.replace("/".toRegex(), "|") + ".dat"
    }

    @JvmStatic
    fun init(application: Application) {
        mApplication = application
    }

    @JvmStatic
    fun remove(key: String): Boolean {
        val cache = remove(key, true)
        val noBackup = remove(key, false)
        return cache || noBackup
    }

    @JvmStatic
    fun remove(key: String, isCache: Boolean): Boolean {
        val fileName = toFileName(key)
        mLcrCache.remove(fileName)
        val file = File(if (isCache) mCacheFilePath else mNoBackupFilePath + fileName)
        return file.delete()
    }

    @JvmStatic
    fun removeAll() {
        removeAll(true)
        removeAll(false)
    }

    @JvmStatic
    fun removeAll(isCache: Boolean) {
        mLcrCache.evictAll()
        val path = if (isCache) mCacheFilePath else mNoBackupFilePath
        val dirFile = File(path.substring(0, path.length - 1))
        for (one in Objects.requireNonNull(dirFile.listFiles())) {
            one.delete()
        }
    }
}